home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 25 / Mac Magazin and MacEasy Magazine CD - Issue 25.iso / Grafik & Text / BibTeX / Source code / file-io.cp < prev    next >
Text File  |  1996-05-17  |  25KB  |  524 lines

  1. /**************************************************************************
  2. *                                                                         *
  3. * Product:    Bibtex                                                   *
  4. * Module:     File I/O                                                    *
  5. * File:       file-io.cp                                                  *
  6. * Abstract:   The functions in this module are rough equivalents to Unix  *
  7. *             file I/O functions that Bibtex needs.                    *
  8. * Exports:                                                                *
  9. *             CloseFile                                                   *
  10. *             FPrintF                                                     *
  11. *             FPutC                                                       *
  12. *             FPutS                                                       *
  13. *             GetC                                                        *
  14. *             OpenInputFile                                               *
  15. *             OpenOutputFile                                              *
  16. *             UnGetC                                                      *
  17. * History:                                                                *
  18. *     1.0     11-Jul-95   RJZ.  Initial version.                          *
  19. *                                                                         *
  20. **************************************************************************/
  21. #include "CBibTeXApp.h"
  22. #include "bibutils.h"
  23. #include "BibTeX.h"
  24. #include "file-io.h"
  25. #include <stdarg.h>
  26.  
  27. // Local variables:
  28.  
  29.                                         // Output buffer.
  30. static char gBuffer[kBufferSize];
  31.  
  32. /*************************************************************************
  33. *                                                                        *
  34. * Function:   CloseFile                                                  *
  35. * Purpose:    Closes a file.                                             *
  36. * Inputs:     descPtr is a pointer to a file description structure for   *
  37. *             the file to be closed.                                     *
  38. * Outputs:    None.                                                      *
  39. * Exceptions: Throws an exception if an OS error occurs.                 *
  40. * Side Effects:   Closes a file.                                         *
  41. * Design:     In addition to closing the file, this function also        *
  42. *             flushes the volume that contains the file.  IM recommends  *
  43. *             this.                                                      *
  44. * Errors:     Displays an error message if an OS error occurs.           *
  45. * History:                                                               *
  46. *     1.0     10-Jul-95   RJZ.  Initial version.                         *
  47. *                                                                        *
  48. *************************************************************************/
  49. void CloseFile(FileDescPtr descPtr) {
  50.     OSErr err;
  51.  
  52.     if(descPtr) {
  53.         if (descPtr->refNum != 0) {
  54.             err = ::FSClose(descPtr->refNum);
  55.             if (err == noErr)
  56.                 err = ::FlushVol(NULL, descPtr->spec.vRefNum);
  57.             descPtr->refNum = 0;
  58.         }
  59.     //    if (err != noErr) {
  60.     //        FatalOSErr("Problem closing file %s: %s",
  61.     //                    (char *) descPtr->spec.name + 1, err);
  62.     //    }
  63.         delete descPtr;
  64.     }
  65. }
  66.  
  67. // we also set the eof for output files.
  68. void CloseOutputFile(FileDescPtr descPtr) {
  69.     if(descPtr) {
  70.         if (descPtr->refNum != 0) {
  71.             long size;
  72.             GetFPos(descPtr->refNum,&size);
  73.             SetEOF(descPtr->refNum,size);
  74.         }
  75.     }
  76.     CloseFile(descPtr);
  77. }
  78. /**************************************************************************
  79. *                                                                         *
  80. * Function:   FPrintF                                                     *
  81. * Purpose:    Performs formatted I/O to a file.  It is the same as        *
  82. *             fprintf.                                                    *
  83. * Inputs:     descPtr is a pointer to a file description structure, and   *
  84. *             format is a pointer to a format string.  Zero or more       *
  85. *             arguments may follow.                                       *
  86. * Outputs:    The number of bytes written.                                *
  87. * Exceptions: Throws an exception if a write error occurs.                *
  88. * Side Effects:   Writes to a file.                                       *
  89. * Design:     Out of the box, Bibtex uses fprintf to format and print  *
  90. *             error messages.  Here I use vsprintf to format the message  *
  91. *             and then Macintosh file I/O to write the message.  As a     *
  92. *             result, this function behaves just like fprintf.            *
  93. * Errors:     Checks for I/O errors as a result of the call to FSWrite.   *
  94. * History:                                                                *
  95. *     1.0     11-Jul-95   RJZ.  Initial version.                          *
  96. *                                                                         *
  97. **************************************************************************/
  98. long FPrintF(FileDescPtr descPtr, const char *format, ...) {
  99.     va_list args;                       // variable argument list
  100.     long    count;
  101.     OSErr   err;
  102.  
  103.     va_start(args, format);
  104.     count = vsprintf(gBuffer, format, args);
  105.     va_end(args);
  106.     if (count > kBufferSize)
  107.         FPrintFStdErr("Wrote past end of buffer in FPrintF!\r");
  108.     err = ::FSWrite(descPtr->refNum, &count, gBuffer);
  109.     if (err != noErr)
  110.         FatalOSErr("Error while writing to %s: %s",
  111.                    (char *) descPtr->spec.name + 1, err);
  112.     return count;
  113. }
  114.  
  115. /*************************************************************************
  116. *                                                                        *
  117. * Function:   FPrintFStdErr                                              *
  118. * Purpose:    This function is the equivalent of calling fprintf with    *
  119. *             the output directed to stderr.  In this case we send the   *
  120. *             output to the log window.                                  *
  121. * Inputs:     The inputs are the same as for printf.                     *
  122. * Outputs:    The function value is the number of characters displayed.  *
  123. * Exceptions: None.                                                      *
  124. * Side Effects:   Displays characters on the screen.                     *
  125. * Errors:     None.                                                      *
  126. * History:                                                               *
  127. *     1.0     29-Jul-95   RJZ.  Initial version.                         *
  128. *                                                                        *
  129. *************************************************************************/
  130. long FPrintFStdErr(const char *format, ...) {
  131.     va_list args;                       // variable argument list
  132.     long    count;
  133.  
  134.     va_start(args, format);
  135.     count = vsprintf(gBuffer, format, args);
  136.     va_end(args);
  137.     CBibtexApp::DisplayInLogWindow(gBuffer, count);
  138.  
  139.     return count;
  140. }
  141.  
  142. /************************************************************************
  143. *                                                                       *
  144. * Function:   FPutC                                                     *
  145. * Purpose:    Writes a character to a file.                             *
  146. * Inputs:     mess1 is the character to be written.  descPtr points to  *
  147. *             the file where the character will be written.             *
  148. * Outputs:    None.                                                     *
  149. * Exceptions: Throws an exception if an error occurs.                   *
  150. * Side Effects:   Writes to a file.                                     *
  151. * Design:     This function mimics the behavior of the Unix function    *
  152. *             fputc() except that it doesn't have a return value.       *
  153. *             Instead, if an error occurs, it throws an exception.      *
  154. * Errors:     Checks for OS errors from the call to FSWrite.            *
  155. * History:                                                              *
  156. *     1.0     12-Jul-95   RJZ.  Initial version.                        *
  157. *                                                                       *
  158. ************************************************************************/
  159. void FPutC(const char mess1, FileDescPtr descPtr) {
  160.     if(descPtr == 0 ) {
  161.         FPutC(mess1);
  162.         return;
  163.     }
  164.         
  165.     long    count;
  166.     OSErr   err;
  167.     
  168.     count = 1;
  169.     #if 1
  170.     err = ::FSWrite(descPtr->refNum, &count, &mess1);
  171.     #else
  172.     // attempt to use async write, but I get illegal instruction problems!
  173.     IOParam bib_pb; // must be set up elsewhere
  174.     bib_pb.ioVRefNum = descPtr->spec.vRefNum;    // as union member field
  175.     bib_pb.ioRefNum = descPtr->refNum;    // as union member field
  176.     bib_pb.ioPosMode = fsAtMark; // from wherever
  177.     bib_pb.ioReqCount = 1;    // the line size
  178.     char printchar = mess1;
  179.     bib_pb.ioBuffer = &printchar;        // the one character
  180.     err = PBWriteAsync((ParamBlockRec*) &bib_pb);    // write one char
  181.     #endif
  182.     
  183.     if (err != noErr)
  184.         FatalOSErr("Error while writing to %s: %s",
  185.                     (char *) descPtr->spec.name + 1, err);
  186. }
  187.  
  188. /************************************************************************
  189. *                                                                       *
  190. * Function:   FPutC                                                     *
  191. * Purpose:    Writes a character to a file.                             *
  192. * Inputs:     mess1 is the character to be written.  descPtr points to  *
  193. *             the file where the character will be written.             *
  194. * Outputs:    None.                                                     *
  195. * Exceptions: Throws an exception if an error occurs.                   *
  196. * Side Effects:   Writes to a file.                                     *
  197. * Design:     This function mimics the behavior of the Unix function    *
  198. *             fputc() except that it doesn't have a return value.       *
  199. *             Instead, if an error occurs, it throws an exception.      *
  200. * Errors:     Checks for OS errors from the call to FSWrite.            *
  201. * History:                                                              *
  202. *     1.0     12-Jul-95   VMD.  Initial version.                        *
  203. *                                                                       *
  204. ************************************************************************/
  205. void FPutC(const char mess1) {
  206.     long    count = 1;
  207.  
  208.     gBuffer[0] = mess1;
  209.     gBuffer[1] = '\0';
  210.     CBibtexApp::DisplayInLogWindow(gBuffer, count);
  211. }
  212.  
  213. /*************************************************************************
  214. *                                                                        *
  215. * Function:   FPutS                                                      *
  216. * Purpose:    Writes a character string to a file.                       *
  217. * Inputs:     mess1 is the string to be written.  descPtr points to the  *
  218. *             file where the string will be written.                     *
  219. * Outputs:    None.                                                      *
  220. * Exceptions: Throws an exception if an OS error occurs.                 *
  221. * Side Effects:   Writes to a file.                                      *
  222. * Design:     This function mimics the behavior of the Unix function     *
  223. *             fputs() except that it doesn't have a return value.        *
  224. *             Instead, it an error occurs, it throws an exception.       *
  225. * Errors:     Checks for OS errors from the call to FSWrite.             *
  226. * History:                                                               *
  227. *     1.0     12-Jul-95   RJZ.  Initial version.                         *
  228. *                                                                        *
  229. *************************************************************************/
  230. void FPutS(const char *mess1, FileDescPtr descPtr) {
  231.     long    count;
  232.     OSErr   err;
  233.  
  234.     count = strlen(mess1);
  235.     err = ::FSWrite(descPtr->refNum, &count, mess1);
  236.     if (err != noErr)
  237.         FatalOSErr("Error while writing to %s: %s",
  238.                     (char *) descPtr->spec.name + 1, err);
  239. }
  240.  
  241. /**************************************************************************
  242. *                                                                         *
  243. * Function:   FSeek                                                       *
  244. * Purpose:    Changes the position of the file mark.                      *
  245. * Inputs:     descPtr is a pointer to the file description structure for  *
  246. *             the file, offset is how much to change the file mark, and   *
  247. *             "from" indicates how to do the change.                      *
  248. * Outputs:    Returns any OS error that occurs.                           *
  249. * Exceptions: None.                                                       *
  250. * Side Effects:   Moves the file mark.                                    *
  251. * Design:     This function is designed to mimic the behavior of the      *
  252. *             Unix fseek() function.  Use from = 0 if the offset is from  *
  253. *             the start of the file, 1 if the offset is from the current  *
  254. *             mark, and 2 if the offset is from the end of file.  If      *
  255. *             some other (invalid) value is specified, assume that        *
  256. *             offset is from current mark.                                *
  257. * Errors:     Returns any OS error that occurs because fseek() returns a  *
  258. *             non-zero value if an error occurs.                          *
  259. * History:                                                                *
  260. *     1.0     10-Jul-95   RJZ.  Initial version.                          *
  261. *                                                                         *
  262. **************************************************************************/
  263. OSErr FSeek(FileDescPtr descPtr, long offset, short from) {
  264.     OSErr   err;
  265.  
  266.                                         // Translate the meaning of "from" from
  267.                                         // its Unix sense to the Macintosh
  268.                                         // equivalent.
  269.     switch (from) {
  270.     case 0:
  271.         from = fsFromStart;
  272.         break;
  273.     case 1:
  274.         from = fsFromMark;
  275.         break;
  276.     case 2:
  277.         from = fsFromLEOF;
  278.         break;
  279.     default:
  280.         from = fsAtMark;
  281.     }
  282.     err = ::SetFPos(descPtr->refNum, from, offset);
  283.  
  284.     return err;
  285. }
  286.  
  287. /**************************************************************************
  288. *                                                                         *
  289. * Function:   GetC                                                        *
  290. * Purpose:    Reads a character from a file.                              *
  291. * Inputs:     descPtr is a pointer to the file description structure for  *
  292. *             the file.                                                   *
  293. * Outputs:    The function value is a character returned in a long.       *
  294. * Exceptions: Throws an exception if a read error other than an eof       *
  295. *             occurs.                                                     *
  296. * Side Effects:   Advances position in file.                              *
  297. * Design:     This function is designed to work like the Unix getc()      *
  298. *             function.  That's why it has to return the character it     *
  299. *             reads as a long.  Otherwise, there's no way to return EOF.  *
  300. * Errors:     Posts an alert if an error other that eof occurs.           *
  301. * History:                                                                *
  302. *     1.0     10-Jul-95   RJZ.  Initial version.                          *
  303. *                                                                         *
  304. **************************************************************************/
  305. long GetC(FileDescPtr descPtr) {
  306.     char    c;
  307.     long    count;
  308.     OSErr   err;
  309.  
  310.     count = 1;
  311.     err = ::FSRead(descPtr->refNum, &count, &c);
  312.     if (err != noErr) {
  313.         if (err == eofErr)
  314.             return EOF;
  315.         else
  316.             FatalOSErr("Error reading from file %s: %s",
  317.                         (char *) descPtr->spec.name + 1, err);
  318.     }
  319.     return (unsigned char) ( c == '\n' ? '\r' : c );
  320. }
  321.  
  322. /**************************************************************************
  323. *                                                                         *
  324. * Function:   OpenInputFile                                               *
  325. * Purpose:    Opens an input file for reading.                            *
  326. * Inputs:     descPtr is a pointer to the FileDesc structure of the file  *
  327. *             to be opened.                                               *
  328. * Outputs:    Stuffs the file reference number into the FileDesc          *
  329. *             structure.                                                  *
  330. * Exceptions: Throws an exception if unable to open the file.             *
  331. * Side Effects:   Opens a file.                                           *
  332. * Design:     Originally this was to be an equivalent to the Unix         *
  333. *             open().  However, it's hard to produce an exact equivalent  *
  334. *             to this function on the Macintosh.  For example, open()     *
  335. *             creates a file if it doesn't exist.  That's why I didn't    *
  336. *             give this function a name that was similar to open().       *
  337. * Errors:     Displays a message if unable to open the file.              *
  338. * History:                                                                *
  339. *     1.0     10-Jul-95   Initial version.                                *
  340. *                                                                         *
  341. **************************************************************************/
  342. void OpenInputFile(FileDescPtr descPtr) {
  343.     OSErr   err;
  344.  
  345.     err = ::FSpOpenDF(&descPtr->spec, fsRdPerm, &descPtr->refNum);
  346.     if (err != noErr)
  347.         FatalOSErr("Problem opening file %s: %s",
  348.                     (char *) descPtr->spec.name + 1, err);
  349. }
  350.  
  351. /**************************************************************************
  352. *                                                                         *
  353. * Function:   OpenOutputFile                                              *
  354. * Purpose:    Opens an output file for writing.                           *
  355. * Inputs:     descPtr is a pointer to the FileDesc structure of the file  *
  356. *             to be opened.                                               *
  357. * Outputs:    Stuffs the file reference number into the FileDesc          *
  358. *             structure.                                                  *
  359. * Exceptions: Throws an exception if unable to open the file.             *
  360. * Side Effects:   Opens a file.                                           *
  361. * Design:     Originally this was to be an equivalent to the Unix         *
  362. *             open().  However, it's hard to produce an exact equivalent  *
  363. *             to this function on the Macintosh.  For example, open()     *
  364. *             creates a file if it doesn't exist.  That's why I didn't    *
  365. *             give this function a name that was similar to open().       *
  366. * Errors:     Displays a message if unable to open the file.              *
  367. * History:                                                                *
  368. *     1.0     10-Jul-95   Initial version.                                *
  369. *                                                                         *
  370. **************************************************************************/
  371. void OpenOutputFile(FileDescPtr descPtr) {
  372.     OSErr   err;
  373.  
  374.     err = ::FSpOpenDF(&descPtr->spec, fsWrPerm, &descPtr->refNum);
  375.     if (err != noErr)
  376.         FatalOSErr("Problem opening file %s: %s",
  377.                     (char *) descPtr->spec.name + 1, err);
  378. }
  379.  
  380. /**************************************************************************
  381. *                                                                         *
  382. * Function:   UnGetC                                                      *
  383. * Purpose:    Puts back a character that was just read.                   *
  384. * Inputs:     ch is the character just read and descPtr is a pointer to   *
  385. *             the file description structure.                             *
  386. * Outputs:    noErr if successful, EOF if unsuccessful or if ch is EOF.   *
  387. * Exceptions: None.                                                       *
  388. * Side Effects:   Moves the file mark.                                    *
  389. * Design:     This works like the Unix function ungetc().  Note that      *
  390. *             this function will not work for the idx file since the      *
  391. *             input for that file is buffered.  If it becomes necessary   *
  392. *             to use UnGetC() on the idx file in the future, it           *
  393. *             will be necessary to stop using buffered input for the idx  *
  394. *             file or maybe it will be necessary to create a special      *
  395. *             version of this function for the idx file.                  *
  396. * Errors:     None.                                                       *
  397. * History:                                                                *
  398. *     1.0     10-Jul-95   RJZ.  Initial version.                          *
  399. *                                                                         *
  400. **************************************************************************/
  401. int UnGetC(int ch, FileDescPtr descPtr) {
  402.     OSErr   err;
  403.  
  404.     if (ch != EOF) {
  405.         err = ::SetFPos(descPtr->refNum, fsFromMark, -1L);
  406.         if (err == noErr)
  407.             return noErr;
  408.         else
  409.             return EOF;
  410.     } else
  411.         return EOF;
  412. }
  413.  
  414. boolean    FEof(FileDescPtr descPtr) {
  415.     long end;
  416.     GetEOF(descPtr->refNum, &end);
  417.     long curr;
  418.     GetFPos(descPtr->refNum, &curr);
  419.  
  420.     return (end == curr);
  421. }
  422.  
  423. // not static because it needs to be reset each run.
  424. FileDescPtr myBufferedFile;
  425.  
  426. long GetBibtexCharacter(FileDescPtr descPtr) {
  427.     static short    bufferPos;          // next char to come out of readBuffer
  428.     long            count;              // number of characters to read
  429.     OSErr           err;                // error code
  430.     static char     readBuffer[kReadBufferSize];
  431.     extern FileDescPtr myBufferedFile;
  432.     static short myFileEnd;
  433.     static long myFilePos;
  434.     
  435.     if(myBufferedFile != descPtr)  {
  436.         // move pos in old file
  437.         if(myBufferedFile)
  438.             SetFPos(myBufferedFile->refNum,fsFromStart, myFilePos);
  439.         // do new file
  440.         myBufferedFile = descPtr;
  441.         bufferPos = 0;
  442.         myFileEnd = -1;
  443.         GetFPos(myBufferedFile->refNum, &myFilePos);
  444.     }
  445.     
  446.     if(bufferPos == myFileEnd){
  447.         // now we really are at the end
  448.         long end;
  449.         GetEOF(myBufferedFile->refNum, &end);
  450.         SetFPos(myBufferedFile->refNum, fsFromStart, end);
  451.         return EOF;
  452.     }
  453.     
  454.     if(bufferPos % kReadBufferSize == 0)  {
  455.         count = kReadBufferSize;
  456.         err = ::FSRead(descPtr->refNum, &count, readBuffer);
  457.         if (err != noErr) {
  458.             if(err == eofErr)  {
  459.                 myFileEnd = count;
  460.                 // pretend we're not at the end yet
  461.                 SetFPos(myBufferedFile->refNum, fsFromLEOF, -2);
  462.             } else {
  463.                 FatalOSErr("Error while reading %s: %s", (char*) myBufferedFile->spec.name, err);
  464.             }
  465.         }
  466.         bufferPos = 0;
  467.     }
  468.     myFilePos++;
  469.     
  470.     char c = readBuffer[bufferPos++];
  471.     return (unsigned char) ( c == '\n' ? '\r' : c );    
  472. }
  473.  
  474.  
  475. #define EOL 13    // line delimiter is CR (ASCII 13)
  476.  
  477. /*
  478.     ReadLine reads a line of text from the file represented by pbp.
  479.     It returns -1 if the file is not delimited, or a file manager
  480.     result code (i.e. eofErr.) It places the null terminated string
  481.     in the buffer pointed to by lineBuf.
  482. */
  483.  
  484. /*
  485. IOParam bib_pb; // must be set up elsewhere
  486. extern char* buffer;
  487.  
  488. void ReadLine(FileDescPtr descPtr) // fixed:, char *lineBuf, const int size)
  489. {    
  490.     extern long last; // BibTeX uses this to keep track of how much was read
  491.     bib_pb.ioVRefNum = descPtr->spec.vRefNum;    // as union member field
  492.     bib_pb.ioRefNum = descPtr->refNum;    // as union member field
  493.  
  494.     OSErr rc = PBReadSync((ParamBlockRec*) &bib_pb);    // read one line
  495.     last = bib_pb.ioActCount;
  496.     
  497.     if (rc==eofErr && last==0){
  498.         return;        // end of file reached
  499.     }
  500.     
  501.     if ((rc==noErr) || (rc==eofErr)) {
  502.         if (last==bufsize) {
  503.             short in = buffer[last-1];
  504.             // skip past eoln if buffer full
  505.             while (in != EOF && in != EOL )
  506.                 in = GetC(descPtr);
  507.             return;    // not a delimited file
  508.         }
  509.         if (buffer[last-1] == EOL) // last line has no EOL
  510.             last--;    
  511.     }
  512.  
  513. }
  514.  
  515. */
  516.       // for speed in the crucial readline routine, we set these up once only
  517.     /* These would have to be put somewhere if we used the above routine
  518.     extern IOParam bib_pb;
  519.     bib_pb.ioPosMode = fsAtMark | 0x80 | (256*13); // just read a line; EOL = 13
  520.     bib_pb.ioReqCount = bufsize;    // max line size
  521.     bib_pb.ioBuffer = buffer;        // transfer to this address
  522.     */
  523.  
  524.